// Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

using BL = PfRep.Library;
using DA = PfRep.DataEntities;
using PfRep.DataEntities;

namespace PfRep.Console
{
    public partial class MainWindow : Form
    {
        #region Local variables
        /// <summary>
        /// The selected folder tree's ID on the Select Datasource dialog
        /// </summary>
        private int selectedFolderTreeId = 0;
        
        /// <summary>
        /// The selected content index ID on the Select Datasource dialog
        /// </summary>
        private int selectedContentIndexId = 0;
        
        /// <summary>
        /// Indicates whether folder contents should be shown in the OWA window
        /// </summary>
        private bool showFolderContents = true;
        
        /// <summary>
        /// Indicates whether legend needs to be shown
        /// </summary>
        private bool showLegend = true;

        /// <summary>
        /// Indicates that the form is initializing
        /// </summary>
        private bool initializing = true;
        #endregion

        #region Helpers
        /// <summary>
        /// Pops up the options dialog
        /// </summary>
        private void PopupOptionsDialog()
        {
            Options optionsDialog = new Options();
            optionsDialog.Show();
        }

        /// <summary>
        /// Creates subnodes under a tree node
        /// </summary>
        /// <param name="treeNode">Tree node</param>
        /// <param name="folders">Subnodes</param>
        private void FillUpNodeWithFolders(TreeNode treeNode, List<DA.Folder> folders)
        {
            // If the node's subnodes are already filled up, exiting
            if (treeNode.Nodes.Count > 0)
                return;
            
            // Creates the nodes under the tree node
            foreach (DA.Folder folder in folders)
            {
                // Create the new sub-node
                TreeNode newSubNode = 
                    treeNode.Nodes.Add(folder.ID.ToString(), 
                    folder.Name + " (" + folder.ItemCount + ")  ");
                
                // Tag contains the folder object itself
                newSubNode.Tag = folder;

                // If there's no owner, we set the font to bold
                if (string.IsNullOrEmpty(folder.OwnerName) || folder.OwnerName.Length == 0)
                    newSubNode.NodeFont = new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Bold);

                // Color the folder icon
                string folderIcon = "";
                
                if (folder.Indexed == false)
                    folderIcon = "noindexed";
                else if (folder.LastModified == DateTime.MinValue)
                    folderIcon = "empty";
                else if (folder.PassedSinceLastModification.Days < -180)
                    folderIcon = "boring";
                else if (folder.PassedSinceLastModification.Days < -60)
                    folderIcon = "belownormal";
                else if (folder.PassedSinceLastModification.Days < -30)
                    folderIcon = "normal";
                else if (folder.PassedSinceLastModification.Days < -10)
                    folderIcon = "busy";
                else
                    folderIcon = "verybusy";
                    
                // Set the folder icon
                newSubNode.ImageKey = folderIcon;
                newSubNode.SelectedImageKey = folderIcon;

                // Set the fore color based on the item count
                if (folder.ItemCount < 50)
                    newSubNode.ForeColor = Color.Black;
                else if (folder.ItemCount < 200)
                    newSubNode.ForeColor = Color.Blue;
                else
                    newSubNode.ForeColor = Color.Red;
            }
        }

        /// <summary>
        /// Ensures that the given node's subfolders are filled up for 2 levels in order to have
        /// the plus sign if there are subfolders
        /// </summary>
        /// <param name="treeNode"></param>
        private void EnsureFolderNodeIsFilled(TreeNode treeNode)
        {
            int folderId = 0;

            if (treeNode.Tag != null)
                folderId = ((DA.Folder)treeNode.Tag).ID;
            
            // Fills up the given folder's subfolders
            FillUpNodeWithFolders(treeNode, 
                BL.Statistics.GetSubfolders(folderId, selectedFolderTreeId, selectedContentIndexId));

            // Fills up the subfolders to have the plus sign if there are subfolders
            foreach (TreeNode subNode in treeNode.Nodes)
            {
                FillUpNodeWithFolders(
                    subNode, BL.Statistics.GetSubfolders(
                    ((DA.Folder)subNode.Tag).ID, selectedFolderTreeId, selectedContentIndexId));
            }
        }

        /// <summary>
        /// Pops up the Manage Datasources window and allows the user to
        /// select a datasource
        /// </summary>
        /// <returns>A boolean indicating whether the datasource was selected
        /// or the Cancel button was pressed. 
        /// true = selected, false = Cancel pressed.</returns>
        private bool SelectDataSource()
        {
            // Pops up the Select Datasource dialog
            using (ManageDataSources manageDatasources = new ManageDataSources())
            {
                manageDatasources.ShowDialog(this);

                // If the user has cancelled, let's exit
                if (manageDatasources.UserCancelled)
                    return false;

                // Gets the selected folder tree Id
                if (manageDatasources.SelectedFolderTree == null || 
                    manageDatasources.SelectedFolderTree.ID == 0)
                    return false;
                else
                {
                    selectedFolderTreeId = manageDatasources.SelectedFolderTree.ID;
                    selectedContentIndexId = manageDatasources.SelectedContentStatisticId;
                }
            }

            // Create a root node in the tree
            FolderTreeStructure.Nodes.Clear();
            TreeNode rootNode = FolderTreeStructure.Nodes.Add("0", "All Public Folders");

            // Fill up the root node
            EnsureFolderNodeIsFilled(rootNode);

            // Expand the root nodes
            rootNode.Expand();

            // Fills up the action plans combo
            ActionPlan.Items.Clear();
            ActionPlan.Items.AddRange(BL.Statistics.GetActionPlans().ToArray());
            ActionPlan.DisplayMember = "Value";
            ActionPlan.ValueMember = "Key";

            return true;
        }

        /// <summary>
        /// Runs actions relying on a selected tree node
        /// </summary>
        private void TreeNodeSelected()
        {
            // Retrieves the selected folder from the tree
            Folder selectedFolder = (Folder)FolderTreeStructure.SelectedNode.Tag;

            // Fills up the folder properties (right top bar) if there's a folder
            //  selected. If the "All Public Folders" node is selected, there's
            //  no folder object in the Tag property!
            if (selectedFolder != null)
            {
                // Shows the folder properties
                FolderName.Text = selectedFolder.Name;
                IsContentIndexed.Text = selectedFolder.Indexed.ToString();
                ItemCount.Text = selectedFolder.ItemCount.ToString();
                OwnerName.Text = selectedFolder.OwnerName;
                OwnerEmail.Text = selectedFolder.OwnerEmail;
                ActionPlan.Text = selectedFolder.ActionPlanName;
                folderNote.Text = selectedFolder.Note;

                // Counts the time passed since last modification
                TimeSpan lastModifiedSpan = selectedFolder.PassedSinceLastModification;
                ContentLastModified.Text =
                    (lastModifiedSpan.Days != 0 ?
                    (lastModifiedSpan.Days * -1).ToString() + " days" :
                    (lastModifiedSpan.Hours * -1).ToString() + " hours")
                    + " ago";

                // Navigates to the Exchange folder
                if (showFolderContents)
                    FolderContents.Navigate(selectedFolder.Key + "?Cmd=contents");

                // Set the buttons
                cmdSave.Enabled = true;
            }
            else
            {
                // Set the buttons
                cmdSave.Enabled = false;
            }

        }

        /// <summary>
        /// Saves the folder settings recursively
        /// </summary>
        /// <param name="rootFolder">Root folder to update 
        /// (should contain the updated properties)</param>
        private void SaveRecursively(
            DA.Folder rootFolder)
        {
            // Update the given folder
            BL.Statistics.UpdateFolder(rootFolder);

            // Retrieves the subfolders
            List<DA.Folder> subFolders = BL.Statistics.GetSubfolders(
                rootFolder.ID, selectedFolderTreeId, selectedContentIndexId);

            // Updates them recursively
            if (subFolders != null && subFolders.Count > 0)
            {
                foreach (DA.Folder subFolder in subFolders)
                {
                    // Copy the changed values on the subfolder
                    subFolder.OwnerName = rootFolder.OwnerName;
                    subFolder.OwnerEmail = rootFolder.OwnerEmail;
                    subFolder.ActionPlan = rootFolder.ActionPlan;
                    subFolder.ActionPlanName = rootFolder.ActionPlanName;

                    // Calls update recursively
                    SaveRecursively(subFolder);
                }
            }
        }
        #endregion

        #region Event handlers
        /// <summary>
        /// Form initializer
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Form initialization
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            // Refresh the local variable indicating whether to show folder contents
            showFolderContents =
                string.Compare("True",
                Common.Config.GetConfigValue(Common.Config.PARAM_SHOW_FOLDER_CONTENTS), true) == 0 ?
                true : false;

            // Sets the properties on the UI
            folderContentsToolStripMenuItem.Checked = showFolderContents;

            // Refresh the local variable indicating whether to show legend
            showLegend = 
                string.Compare("True",
                Common.Config.GetConfigValue(Common.Config.PARAM_SHOW_FOLDER_CONTENTS), true) == 0 ?
                true : false;

            // Sets the checkbox
            legendToolStripMenuItem.Checked = showLegend;

            // Shows or hides the Legend
            if (showLegend)
                Legend.Visible = true;
            else
                Legend.Visible = false;

            // Set the flag that inidicates that the form is initializing.
            //  This is used to select the first node after the tree is filled up
            initializing = true;

            // Pop up a Select Data source window. If the user cancelled, we close the app,
            //  as there's no initial data to work with.
            if (!SelectDataSource())
                this.Close();
        }

        /// <summary>
        /// Makes sure that the nodes are generated into the folder tree
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FolderTreeStructure_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            EnsureFolderNodeIsFilled(e.Node);

            // If there's any item in the tree structure, let's jump to the first one!
            if (initializing && FolderTreeStructure.Nodes.Count > 0 
                && FolderTreeStructure.Nodes[0].Nodes.Count > 1)
            {
                FolderTreeStructure.SelectedNode = FolderTreeStructure.Nodes[0].Nodes[0];
                initializing = false;
            }
        }

        /// <summary>
        /// Fires when a node is selected
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FolderTreeStructure_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // Run actions relying on a selected tree node
            TreeNodeSelected();
        }

        /// <summary>
        /// The owner combo drops down: a user typed in 
        /// there is looked up in AD
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OwnerName_DropDown(object sender, EventArgs e)
        {
            // Clear the combo and set it up
            OwnerName.Items.Clear();
            OwnerName.DisplayMember = "Value";
            OwnerName.ValueMember = "Key";
            
            // Fill up with results
            if (OwnerName.Text.Length > 2)
                OwnerName.Items.AddRange(BL.Statistics.GetUsers(OwnerName.Text).ToArray());
            else
                OwnerName.Items.Add(new KeyValuePair<string, string>("", "Type at least 3 letters"));
        }

        /// <summary>
        /// An owner is selected and his/her email address gets shown
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OwnerName_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (OwnerName.SelectedItem != null)
            {
                // Retrieve the selected item
                string ownerEmail = ((KeyValuePair<string, string>)OwnerName.SelectedItem).Key;

                // If there's no email address, don't select it. Otherwise, show the email address
                if (ownerEmail.Length == 0)
                    OwnerName.Text = "";
                else
                    OwnerEmail.Text = ownerEmail;
            }
        }

        /// <summary>
        /// Save a folder's owner and action plan
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdSave_Click(object sender, EventArgs e)
        {
            // Retrieves the selected folder from the tree
            Folder selectedFolder = (Folder)FolderTreeStructure.SelectedNode.Tag;

            // Cast the action plan value
            DataEntities.ActionPlan actionPlan = DataEntities.ActionPlan.MigrateToSharePoint;
            if (ActionPlan.SelectedIndex >= 0)
                actionPlan = 
                    (DataEntities.ActionPlan)((KeyValuePair<int, string>)ActionPlan.SelectedItem).Key;

            // Update the folder in memory
            selectedFolder.OwnerName = OwnerName.Text;
            selectedFolder.OwnerEmail = OwnerEmail.Text;
            selectedFolder.ActionPlan = actionPlan;
            selectedFolder.ActionPlanName = ActionPlan.Text;
            selectedFolder.Note = folderNote.Text;

            // If there's no owner, we set the font to bold
            if (string.IsNullOrEmpty(selectedFolder.OwnerName) || selectedFolder.OwnerName.Length == 0)
                FolderTreeStructure.SelectedNode.NodeFont =
                    new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Bold);
            else
                FolderTreeStructure.SelectedNode.NodeFont =
                    new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Regular);

            // Update recursively
            if (chkRecursive.Checked)
            {
                this.Cursor = Cursors.WaitCursor;
                
                // Recursive function
                SaveRecursively(selectedFolder);

                this.Cursor = Cursors.Arrow;

                // Clear the current node and selected nodes
                //  to make sure it refreshes
                FolderTreeStructure.SelectedNode.Nodes.Clear();

                // Update it
                EnsureFolderNodeIsFilled(FolderTreeStructure.SelectedNode);
            }
            
            // Update only one folder
            else
            {
                // Update folder
                BL.Statistics.UpdateFolder(selectedFolder);
            }
        }

        /// <summary>
        /// Cleans up the email address
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OwnerName_TextChanged(object sender, EventArgs e)
        {
            if (OwnerName.Text.Length == 0)
                OwnerEmail.Text = "";
        }
        #endregion

        #region Top menu event handlers
        /// <summary>
        /// Options dialog window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PopupOptionsDialog();
        }
        
        /// <summary>
        /// New datasource selection
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void selectmanageDatasourcesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SelectDataSource();
        }

        /// <summary>
        /// Exit menu
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Store the "Show folder contents" value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void folderContentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Set the checkbox to the other state
            folderContentsToolStripMenuItem.Checked = !folderContentsToolStripMenuItem.Checked;

            // Save the config value
            Common.Config.SetConfigValue(Common.Config.PARAM_SHOW_FOLDER_CONTENTS,
                folderContentsToolStripMenuItem.Checked.ToString());

            //Refresh the local variable indicating whether to show folder contents
            showFolderContents = folderContentsToolStripMenuItem.Checked;

            // If the option becomes checked now, refresh the selection
            if (showFolderContents)
                TreeNodeSelected();
            else
                FolderContents.Navigate("");
        }

        /// <summary>
        /// Show/hide legend
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void legendToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Set the checkbox to the other state
            legendToolStripMenuItem.Checked = !legendToolStripMenuItem.Checked;

            // Save the config value
            Common.Config.SetConfigValue(Common.Config.PARAM_SHOW_LEGEND,
                legendToolStripMenuItem.Checked.ToString());

            //Refresh the local variable indicating whether to show folder contents
            showLegend = legendToolStripMenuItem.Checked;

            // If the option becomes checked now, refresh the selection
            if (showLegend)
                Legend.Visible = true;
            else
                Legend.Visible = false;
        }
        #endregion

        /// <summary>
        /// TODO: Email to the owner
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OwnerEmail_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {

        }
    }
}